/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.core; import java.awt.datatransfer.*; import java.awt.event.*; import java.awt.Window; import java.io.IOException; import javax.swing.Timer; import java.util.ArrayList; import org.openide.util.datatransfer.ExClipboard; import org.openide.util.RequestProcessor; import org.openide.util.Utilities; import org.openide.TopManager; /** Clipboard workaround about the bug in the Windows system clipboard. * This clipboard maintains connection to the system clipboard and * synchronizes with its content. If a flavour is inserted to the clipboard * that is not accepted by the system one, this clipboard held a reference * to it. * * @author Jaroslav Tulach, Petr Hamernik * @version 0.19, Jun 08, 1998 */ public class CoronaClipboard extends ExClipboard { /** how often to test the change */ private static final int TIME = 3000; /** empty array of flavors */ private static final DataFlavor[] NONE = new DataFlavor[0]; /** a set of all convertors */ private static ArrayList convertors = new ArrayList (); /** array of convertors */ private static Convertor[] array; /** second clipboard */ private Clipboard nextClipboard; /** flavors of the old clipboard */ private DataFlavor[] flavors; /** original transferable */ private Transferable orignalTransferable; /** * Initializes this clipboard to work with system one * @param name name of clipboard */ public CoronaClipboard (String name) { this (name, java.awt.Toolkit.getDefaultToolkit ().getSystemClipboard ()); } /** * Initializes this clipboard to work with the parameter. * @param name name of clipboard * @param clipboard the second clipboard */ public CoronaClipboard (String name, Clipboard clipboard) { super (name); nextClipboard = clipboard; // XXX(-trung) getTransferDataFlavors() causes deadlock on JDK 1.3 beta // Linux and Solaris. See refreshClipboard() if (Utilities.isUnix()) return; // XXX(-trung) Timer t = new Timer (TIME, new ActionListener () { public void actionPerformed (ActionEvent ev) { refreshClipboard (); } }); t.setRepeats (true); t.start (); refreshClipboard (); } /** Changes the content of transferable also notifies the previous one, * that is lost ownership of clipboard. */ synchronized final void changeTransferable (Transferable t) { if (orignalTransferable != null) { transferableOwnershipLost (orignalTransferable); } orignalTransferable = t; } /** Refresh the contents of the external clipboard with * the same content. This method sets * the contents of external clipboard and waits for a change * from outside application. As soon as the change occurs the * <CODE>lostOwnership()</CODE> call occurs which causes a new * call to this method. So all the changes to external clipboard * should be catched except the change after setting contents to null. * <CODE>refreshLost</CODE> flag handles this situation. * * @return change event has been fired or false if not */ synchronized boolean refreshClipboard() { // XXX(-trung) getTransferDataFlavors() causes deadlock on JDK 1.3 beta // Linux and Solaris if (Utilities.isUnix()) return false; // XXX(-trung) Transferable tran = nextClipboard.getContents(this); if (Utilities.isUnix ()) { tran = unixString (tran); } // print (tran); try { DataFlavor[] arr = tran.getTransferDataFlavors (); if (arr == null) { arr = NONE; } if (!java.util.Arrays.equals (arr, flavors)) { // changed flavors flavors = arr; changeTransferable (null); fireClipboardChange (); return true; } } catch (NullPointerException e) { } return false; } /** Sets the content to this clipboard and also to the second one. * Registers to receive notification about lost of ownership and reacts * to such action by clearing content of this clipboard. */ public synchronized void setContents ( Transferable contents, ClipboardOwner owner ) { changeTransferable (contents); nextClipboard.setContents (convert (contents), owner); if (!refreshClipboard ()) { fireClipboardChange (); } } /** Getter that delegates to the provided clipboard. */ public synchronized Transferable getContents (Object requestor) { Transferable t = nextClipboard.getContents (requestor); t = convert (t); if (Utilities.isUnix ()) { // create unix wraper to work on solaris return unixString (t); } else { return t; } } /** Current set of convertors */ protected Convertor[] getConvertors () { return computeConvertors (); } /** test for JDK 1.3 */ private static boolean jdk13 = System.getProperty ("java.vm.version").startsWith ("1.3"); // NOI18N /** Test for string on Unix machines (solaris especially) */ private Transferable unixString (Transferable t) { if (jdk13) { // do not try to run this code on jdk 1.3, because the implementation of // clipboard access is better return t; } DataFlavor[] df = t.getTransferDataFlavors (); if (df == null || df.length == 0) { final Thread[] th = new Thread[] { Thread.currentThread () }; // test for string but prevent from being deadlocked try { try { class Run extends Exception implements Runnable { public void run () { synchronized (th) { // synchronized on th so we are sure that the // the original thread is either before section // marked as XXX or after it Thread x = th[0]; if (x != null) { ClipboardDeadlockException ex = new ClipboardDeadlockException (); // TopManager.getDefault ().getErrorManager ().annotate (ex, this); x.stop (ex); x.interrupt (); } } } } RequestProcessor.postRequest (new Run (), 100); String o = (String)t.getTransferData (DataFlavor.stringFlavor); th[0] = null; StringSelection ss = new StringSelection (o); super.setContents (ss, ss); changeTransferable (null); return ss; } catch (Exception e) { // consume any exception, } finally { synchronized (th) { // clear the thread not to be stopped again th[0] = null; } } } catch (ClipboardDeadlockException ex) { // be sure } } // otherwise use original return t; } /** Adds new convertor to the clipboard. */ static synchronized void addConvertor (Convertor c) { array = null; convertors.add (c); } /** Removes a convertor from the clipboard. */ static synchronized void removeConvertor (Convertor c) { array = null; convertors.remove (c); } /** Computes all convertors. */ private static synchronized Convertor[] computeConvertors () { if (array == null) { array = new Convertor[convertors.size ()]; convertors.toArray (array); } return array; } /* static void print (Transferable contents) { if (contents == null) { System.out.println ("null"); return; } System.out.println ("Content type: " + contents.getClass ().getName ()); DataFlavor[] arr = contents.getTransferDataFlavors (); if (arr == null) { System.out.println ("null"); return; } for (int i = 0; i < arr.length; i++) { try { Object c = contents.getTransferData (arr[i]); if (c instanceof java.io.StringReader) { java.io.StringReader r = (java.io.StringReader)c; char[] cbuf = new char[1024]; int l = r.read (cbuf); c = new String (cbuf, 0, l); } System.out.println (i + ". " + arr[i].getHumanPresentableName () + " content: " + c); } catch (Exception ex) { ex.printStackTrace(); } } } */ } /* * Log * 13 Gandalf 1.12 1/18/00 Jaroslav Tulach Fires changes often. * 12 Gandalf 1.11 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 11 Gandalf 1.10 10/6/99 Jaroslav Tulach #3973 * 10 Gandalf 1.9 6/30/99 Jaroslav Tulach Drag and drop support * 9 Gandalf 1.8 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 8 Gandalf 1.7 3/4/99 Jaroslav Tulach API cleaning * 7 Gandalf 1.6 3/2/99 Jaroslav Tulach * 6 Gandalf 1.5 2/26/99 Jaroslav Tulach Deadlock enhancement. * 5 Gandalf 1.4 2/25/99 Jaroslav Tulach Change of clipboard * management * 4 Gandalf 1.3 2/24/99 Jaroslav Tulach Convertors & clipboard * deadlock * 3 Gandalf 1.2 2/21/99 Jaroslav Tulach Synchronization of * source with X2 * 2 Gandalf 1.1 2/11/99 Jaroslav Tulach Shares data with system * clipboard * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ * Beta Change History: * 0 Tuborg 0.17 --/--/98 Miloslav Metelk added getContents() * 0 Tuborg 0.18 --/--/98 Miloslav Metelk patched getContents() * 0 Tuborg 0.19 --/--/98 Jan Formanek patch for Solaris */